/**
 * 字符串格式化工具类
 * @description 提供各种字符串处理和格式化功能
 */
export class StringUtils {
  /**
   * 截断字符串并添加省略号
   * @param str 原字符串
   * @param maxLength 最大长度
   * @param suffix 后缀（默认为...）
   * @returns 截断后的字符串
   */
  static truncate(str: string, maxLength: number, suffix: string = '...'): string {
    if (!str || typeof str !== 'string') {
      return '';
    }

    if (str.length <= maxLength) {
      return str;
    }

    return str.substring(0, maxLength - suffix.length) + suffix;
  }

  /**
   * 首字母大写
   * @param str 字符串
   * @returns 首字母大写的字符串
   */
  static capitalize(str: string): string {
    if (!str || typeof str !== 'string') {
      return '';
    }

    return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
  }

  /**
   * 每个单词首字母大写
   * @param str 字符串
   * @returns 每个单词首字母大写的字符串
   */
  static capitalizeWords(str: string): string {
    if (!str || typeof str !== 'string') {
      return '';
    }

    return str.replace(/\b\w/g, (char) => char.toUpperCase());
  }

  /**
   * 驼峰命名转换为短横线命名
   * @param str 驼峰命名字符串
   * @returns 短横线命名字符串
   */
  static camelToKebab(str: string): string {
    if (!str || typeof str !== 'string') {
      return '';
    }

    return str.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();
  }

  /**
   * 短横线命名转换为驼峰命名
   * @param str 短横线命名字符串
   * @returns 驼峰命名字符串
   */
  static kebabToCamel(str: string): string {
    if (!str || typeof str !== 'string') {
      return '';
    }

    return str.replace(/-([a-z])/g, (_, char) => char.toUpperCase());
  }

  /**
   * 移除字符串中的HTML标签
   * @param str 包含HTML的字符串
   * @returns 纯文本字符串
   */
  static stripHtml(str: string): string {
    if (!str || typeof str !== 'string') {
      return '';
    }

    return str.replace(/<[^>]*>/g, '');
  }

  /**
   * 转义HTML特殊字符
   * @param str 原字符串
   * @returns 转义后的字符串
   */
  static escapeHtml(str: string): string {
    if (!str || typeof str !== 'string') {
      return '';
    }

    const htmlEscapes: Record<string, string> = {
      '&': '&amp;',
      '<': '&lt;',
      '>': '&gt;',
      '"': '&quot;',
      "'": '&#39;'
    };

    return str.replace(/[&<>"']/g, (char) => htmlEscapes[char]);
  }

  /**
   * 反转义HTML特殊字符
   * @param str 转义后的字符串
   * @returns 原字符串
   */
  static unescapeHtml(str: string): string {
    if (!str || typeof str !== 'string') {
      return '';
    }

    const htmlUnescapes: Record<string, string> = {
      '&amp;': '&',
      '&lt;': '<',
      '&gt;': '>',
      '&quot;': '"',
      '&#39;': "'"
    };

    return str.replace(/&(?:amp|lt|gt|quot|#39);/g, (entity) => htmlUnescapes[entity]);
  }

  /**
   * 生成随机字符串
   * @param length 长度
   * @param charset 字符集
   * @returns 随机字符串
   */
  static generateRandomString(
    length: number, 
    charset: string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
  ): string {
    let result = '';
    for (let i = 0; i < length; i++) {
      result += charset.charAt(Math.floor(Math.random() * charset.length));
    }
    return result;
  }

  /**
   * 生成唯一ID
   * @param prefix 前缀
   * @returns 唯一ID
   */
  static generateUniqueId(prefix: string = ''): string {
    const timestamp = Date.now().toString(36);
    const randomStr = Math.random().toString(36).substr(2, 9);
    return prefix ? `${prefix}_${timestamp}_${randomStr}` : `${timestamp}_${randomStr}`;
  }

  /**
   * 格式化文件大小
   * @param bytes 字节数
   * @param decimals 小数位数
   * @returns 格式化后的文件大小
   */
  static formatFileSize(bytes: number, decimals: number = 2): string {
    if (bytes === 0) return '0 B';

    const k = 1024;
    const dm = decimals < 0 ? 0 : decimals;
    const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];

    const i = Math.floor(Math.log(bytes) / Math.log(k));

    return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
  }

  /**
   * 格式化手机号显示
   * @param phone 手机号
   * @param maskMiddle 是否遮蔽中间数字
   * @returns 格式化后的手机号
   */
  static formatPhone(phone: string, maskMiddle: boolean = false): string {
    if (!phone || typeof phone !== 'string') {
      return '';
    }

    // 移除所有非数字字符
    const cleanPhone = phone.replace(/\D/g, '');

    if (cleanPhone.length === 11) {
      if (maskMiddle) {
        return `${cleanPhone.slice(0, 3)}****${cleanPhone.slice(7)}`;
      } else {
        return `${cleanPhone.slice(0, 3)} ${cleanPhone.slice(3, 7)} ${cleanPhone.slice(7)}`;
      }
    }

    return phone;
  }

  /**
   * 格式化身份证号显示
   * @param idCard 身份证号
   * @param maskMiddle 是否遮蔽中间数字
   * @returns 格式化后的身份证号
   */
  static formatIdCard(idCard: string, maskMiddle: boolean = true): string {
    if (!idCard || typeof idCard !== 'string') {
      return '';
    }

    const cleanIdCard = idCard.replace(/\s/g, '');

    if (cleanIdCard.length === 18) {
      if (maskMiddle) {
        return `${cleanIdCard.slice(0, 6)}********${cleanIdCard.slice(14)}`;
      } else {
        return `${cleanIdCard.slice(0, 6)} ${cleanIdCard.slice(6, 14)} ${cleanIdCard.slice(14)}`;
      }
    }

    return idCard;
  }

  /**
   * 高亮搜索关键词
   * @param text 原文本
   * @param keyword 关键词
   * @param highlightClass CSS类名
   * @returns 高亮后的HTML字符串
   */
  static highlightKeyword(text: string, keyword: string, highlightClass: string = 'highlight'): string {
    if (!text || !keyword || typeof text !== 'string' || typeof keyword !== 'string') {
      return text || '';
    }

    const escapedKeyword = keyword.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
    const regex = new RegExp(`(${escapedKeyword})`, 'gi');
    
    return text.replace(regex, `<span class="${highlightClass}">$1</span>`);
  }

  /**
   * 计算字符串的字节长度（中文字符按2个字节计算）
   * @param str 字符串
   * @returns 字节长度
   */
  static getByteLength(str: string): number {
    if (!str || typeof str !== 'string') {
      return 0;
    }

    let length = 0;
    for (let i = 0; i < str.length; i++) {
      const charCode = str.charCodeAt(i);
      if (charCode >= 0x4e00 && charCode <= 0x9fff) {
        // 中文字符
        length += 2;
      } else {
        // 其他字符
        length += 1;
      }
    }
    return length;
  }

  /**
   * 按字节长度截断字符串
   * @param str 原字符串
   * @param maxBytes 最大字节数
   * @param suffix 后缀
   * @returns 截断后的字符串
   */
  static truncateByBytes(str: string, maxBytes: number, suffix: string = '...'): string {
    if (!str || typeof str !== 'string') {
      return '';
    }

    if (this.getByteLength(str) <= maxBytes) {
      return str;
    }

    let length = 0;
    let result = '';
    
    for (let i = 0; i < str.length; i++) {
      const char = str.charAt(i);
      const charCode = str.charCodeAt(i);
      const charBytes = (charCode >= 0x4e00 && charCode <= 0x9fff) ? 2 : 1;
      
      if (length + charBytes + this.getByteLength(suffix) > maxBytes) {
        break;
      }
      
      result += char;
      length += charBytes;
    }
    
    return result + suffix;
  }

  /**
   * 移除字符串前后空白字符
   * @param str 字符串
   * @returns 处理后的字符串
   */
  static trim(str: string): string {
    if (!str || typeof str !== 'string') {
      return '';
    }
    return str.trim();
  }

  /**
   * 检查字符串是否为空或只包含空白字符
   * @param str 字符串
   * @returns 是否为空
   */
  static isEmpty(str: string): boolean {
    return !str || typeof str !== 'string' || str.trim().length === 0;
  }

  /**
   * 检查字符串是否不为空
   * @param str 字符串
   * @returns 是否不为空
   */
  static isNotEmpty(str: string): boolean {
    return !this.isEmpty(str);
  }

  /**
   * 将字符串转换为URL友好的格式
   * @param str 原字符串
   * @returns URL友好的字符串
   */
  static toSlug(str: string): string {
    if (!str || typeof str !== 'string') {
      return '';
    }

    return str
      .toLowerCase()
      .trim()
      .replace(/[\s\W-]+/g, '-')
      .replace(/^-+|-+$/g, '');
  }

  /**
   * 格式化模板字符串
   * @param template 模板字符串
   * @param params 参数对象
   * @returns 格式化后的字符串
   */
  static formatTemplate(template: string, params: Record<string, unknown>): string {
    if (!template || typeof template !== 'string') {
      return '';
    }

    return template.replace(/\{(\w+)\}/g, (match, key) => {
      const value = params[key];
      return value !== undefined ? String(value) : match;
    });
  }
}

/**
 * 导出便捷函数
 */

/**
 * 截断字符串
 */
export const truncate = (str: string, maxLength: number, suffix?: string) => 
  StringUtils.truncate(str, maxLength, suffix);

/**
 * 首字母大写
 */
export const capitalize = (str: string) => StringUtils.capitalize(str);

/**
 * 生成唯一ID
 */
export const generateUniqueId = (prefix?: string) => StringUtils.generateUniqueId(prefix);

/**
 * 格式化文件大小
 */
export const formatFileSize = (bytes: number, decimals?: number) => 
  StringUtils.formatFileSize(bytes, decimals);

/**
 * 格式化手机号
 */
export const formatPhone = (phone: string, maskMiddle?: boolean) => 
  StringUtils.formatPhone(phone, maskMiddle);

/**
 * 高亮关键词
 */
export const highlightKeyword = (text: string, keyword: string, highlightClass?: string) => 
  StringUtils.highlightKeyword(text, keyword, highlightClass);

/**
 * 检查字符串是否为空
 */
export const isEmpty = (str: string) => StringUtils.isEmpty(str);

/**
 * 检查字符串是否不为空
 */
export const isNotEmpty = (str: string) => StringUtils.isNotEmpty(str);

/**
 * 格式化模板字符串
 */
export const formatTemplate = (template: string, params: Record<string, unknown>) => 
  StringUtils.formatTemplate(template, params);